package com.example.cscot;

import com.volcengine.ark.runtime.model.completion.chat.ChatCompletionRequest;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessage;
import com.volcengine.ark.runtime.model.completion.chat.ChatMessageRole;
import com.volcengine.ark.runtime.service.ArkService;

import org.json.JSONArray;
import org.json.JSONObject;

import io.reactivex.schedulers.Schedulers;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

//
// https://www.volcengine.com/docs/82379/1302010
// 将示例SDK用法变形成我们的类，变成我们自己熟悉的用法
//
public class DbArk {
    //
    // 豆包鉴权简单方便
    // https://console.volcengine.com/ark/region:ark+cn-beijing/apiKey
    public String mApiKey;
    //
    // 模型选择：
    // https://console.volcengine.com/ark/region:ark+cn-beijing/endpoint
    public String mModel;
    //
    // 真正的豆包方舟大模型后台，Android会下载
    public ArkService mService;
    //
    public String mOnlyResponse;
    //
    public DbArk() {
        // 固定住，愿意的话，以后将其变成可配置，修改构造函数/或者加SetXx()函数
        mApiKey = "0a2f585e-6d9d-4bbc-bfca-e15a415f245b";
        mModel = "ep-20241221093814-qh6t7";
    }
    //
    //
    public int initArk(String strInit) {
        try {
            mService = ArkService.builder().apiKey(mApiKey).build();
        } catch (Exception e) {
            WeiLe.gLogText += LewayHelper.logLine(e.toString());  // 全局log设施一定要在的
            return -1;
        }
        return 0;
    }
    //
    //
    public int uninitArk() {
        // shutdown service
        mService.shutdownExecutor();
        return 0;
    }
    //
    // 豆包的异步利用Schedulers.io()，用Schedulers.single()来保证回调的串行执行
    // 问AI：java中那种new class创建对象和那种build()方式建立对象有什么区别？有什么好处？
    public void postChats(JSONArray pastChats, String userRequest, RtCallback cb) {
        // 防止在主线程中调用网络
        // Java用时现场Override类成员函数定义
        mOnlyResponse = "";
        new Thread(new Runnable() {
            @Override
            public void run() {
                long sttCtms = LewayHelper.CTMS();
                try {
                    // 参数是讯飞更原始，所以是从JSON转成ChatMessage
                    final List<ChatMessage> streamMessages = new ArrayList<>();
                    ChatMessage msg;
                    // 历史聊天处理，可能没有
                    JSONObject jsonObject;
                    String key;
                    for (int i = 0; i < pastChats.length(); i++) {
                        jsonObject = pastChats.getJSONObject(i);
                        // 遍历JSONObject的键值对
                        for (Iterator<String> it = jsonObject.keys(); it.hasNext(); ) {
                            key = it.next();
                            if ((key == "role") && (jsonObject.get(key) == "system")) {
                                msg = ChatMessage.builder().role(ChatMessageRole.SYSTEM)
                                        .content((String) jsonObject.get("content")).build();
                                streamMessages.add(msg);
                            }
                            if ((key == "role") && (jsonObject.get(key) == "user")) {
                                msg = ChatMessage.builder().role(ChatMessageRole.USER)
                                        .content((String) jsonObject.get("content")).build();
                                streamMessages.add(msg);
                            }
                        }
                    }
                    // 当前要问的也加入
                    msg = ChatMessage.builder().role(ChatMessageRole.USER).content(userRequest).build();
                    streamMessages.add(msg);
                    //
                    ChatCompletionRequest streamRequest = ChatCompletionRequest.builder()
                            .model(mModel)
                            .messages(streamMessages)
                            .build();
                    mService.streamChatCompletion(streamRequest)
                            .doOnError(Throwable::printStackTrace)
                            .subscribeOn(Schedulers.io())
                            .observeOn(Schedulers.single())
                            .subscribe(
                                    choice -> {
                                        if (choice.getChoices().size() > 0) {
                                            // 回调函数使用超级简单，牛B
                                            String partialResponse = choice.getChoices().get(0)
                                                    .getMessage().getContent().toString();
                                            mOnlyResponse += partialResponse;
                                            cb.onRightTime(partialResponse);
                                        }
                                    });
                    // Doubao网站描叙的不清楚，无法区分subscribe会被调用几次？如何确定是部分回来，还是全部回来？
                    // 也不需要foreach?
                    // 实测来改正把，可先用time.sleep()再说
                } catch (Exception e) {
                    WeiLe.gLogText += e.toString();
                }
                // 直接返回等着回调
                WeiLe.gLogText += LewayHelper.logLine("postChats now, " + (LewayHelper.CTMS() - sttCtms) + "ms");
            }
        }).start();
        return;
    } // postChats
    //
    // 准备角色设置，就是免得你每次说，假定你是谁/谁，会什么之类的
    public void prepareRole(String whatRole, RtCallback cb) {
        try{
            JSONArray array = new JSONArray();
            WeiLe.gLogText += LewayHelper.logLine(whatRole);
            postChats(array, whatRole, cb);
        } catch(Exception e) {
            WeiLe.gLogText += LewayHelper.logLine(e.toString());
        }
        return;
    } // prepareRole
} // >>> class DbArk
